ಪೈಥಾನ್ ಇಟರೇಶನ್ ಶಕ್ತಿಯನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ. __iter__ ಮತ್ತು __next__ ವಿಧಾನಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಕಸ್ಟಮ್ ಇಟರೇಟರ್ಗಳನ್ನು ಅಳವಡಿಸಲು ಜಾಗತಿಕ ಡೆವಲಪರ್ಗಳಿಗೆ ಸಮಗ್ರ ಮಾರ್ಗದರ್ಶಿ, ಪ್ರಾಯೋಗಿಕ ಉದಾಹರಣೆಗಳೊಂದಿಗೆ.
ಪೈಥಾನ್ನ ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು: __iter__ ಮತ್ತು __next__ ಗೆ ಆಳವಾದ ವಿಶ್ಲೇಷಣೆ
ಪ್ರೋಗ್ರಾಮಿಂಗ್ನಲ್ಲಿ ಇಟರೇಶನ್ ಅತ್ಯಂತ ಮೂಲಭೂತ ಪರಿಕಲ್ಪನೆಗಳಲ್ಲಿ ಒಂದಾಗಿದೆ. ಪೈಥಾನ್ನಲ್ಲಿ, ಇದು ಸರಳ for ಲೂಪ್ಗಳಿಂದ ಹಿಡಿದು ಸಂಕೀರ್ಣ ಡೇಟಾ ಪ್ರಕ್ರಿಯೆ ಪೈಪ್ಲೈನ್ಗಳವರೆಗೆ ಎಲ್ಲವನ್ನೂ ಶಕ್ತಿಗೊಳಿಸುವ ಸೊಗಸಾದ ಮತ್ತು ಪರಿಣಾಮಕಾರಿ ಕಾರ್ಯವಿಧಾನವಾಗಿದೆ. ಪಟ್ಟಿಯ ಮೂಲಕ ಲೂಪ್ ಮಾಡುವಾಗ, ಫೈಲ್ನಿಂದ ಸಾಲುಗಳನ್ನು ಓದುವಾಗ ಅಥವಾ ಡೇಟಾಬೇಸ್ ಫಲಿತಾಂಶಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವಾಗ ನೀವು ಇದನ್ನು ಪ್ರತಿದಿನ ಬಳಸುತ್ತೀರಿ. ಆದರೆ ತೆರೆಯ ಹಿಂದಿನ ಕಾರ್ಯವೈಖರಿ ಏನೆಂದು ನೀವು ಎಂದಾದರೂ ಯೋಚಿಸಿದ್ದೀರಾ? ಇಷ್ಟು ವಿಭಿನ್ನ ರೀತಿಯ ಆಬ್ಜೆಕ್ಟ್ಗಳಿಂದ 'ಮುಂದಿನ' ಐಟಂ ಅನ್ನು ಹೇಗೆ ಪಡೆಯಬೇಕೆಂದು ಪೈಥಾನ್ಗೆ ಹೇಗೆ ಗೊತ್ತು?
ಉತ್ತರವು ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ ಎಂದು ಕರೆಯಲ್ಪಡುವ ಶಕ್ತಿಶಾಲಿ ಮತ್ತು ಸೊಗಸಾದ ವಿನ್ಯಾಸ ಮಾದರಿಯಲ್ಲಿದೆ. ಈ ಪ್ರೋಟೋಕಾಲ್ ಪೈಥಾನ್ನ ಎಲ್ಲಾ ಅನುಕ್ರಮ-ರೀತಿಯ ಆಬ್ಜೆಕ್ಟ್ಗಳು ಮಾತನಾಡುವ ಸಾಮಾನ್ಯ ಭಾಷೆಯಾಗಿದೆ. ಈ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವ ಮತ್ತು ಕಾರ್ಯಗತಗೊಳಿಸುವ ಮೂಲಕ, ನೀವು ಪೈಥಾನ್ನ ಇಟರೇಶನ್ ಪರಿಕರಗಳೊಂದಿಗೆ ಸಂಪೂರ್ಣವಾಗಿ ಹೊಂದಿಕೆಯಾಗುವ ನಿಮ್ಮದೇ ಆದ ಕಸ್ಟಮ್ ಆಬ್ಜೆಕ್ಟ್ಗಳನ್ನು ರಚಿಸಬಹುದು, ನಿಮ್ಮ ಕೋಡ್ ಅನ್ನು ಹೆಚ್ಚು ಅಭಿವ್ಯಕ್ತ, ಮೆಮೊರಿ-ಪರಿಣಾಮಕಾರಿ ಮತ್ತು ಮೂಲಭೂತವಾಗಿ 'ಪೈಥಾನಿಕ್' ಮಾಡಬಹುದು.
ಈ ಸಮಗ್ರ ಮಾರ್ಗದರ್ಶಿ ನಿಮ್ಮನ್ನು ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ಗೆ ಆಳವಾದ ವಿಶ್ಲೇಷಣೆಗೆ ಕರೆದೊಯ್ಯುತ್ತದೆ. ನಾವು `__iter__` ಮತ್ತು `__next__` ವಿಧಾನಗಳ ಹಿಂದಿನ ಮಾಂತ್ರಿಕತೆಯನ್ನು ಬಿಚ್ಚಿಡುತ್ತೇವೆ, ಇಟರಬಲ್ ಮತ್ತು ಇಟರೇಟರ್ ನಡುವಿನ ನಿರ್ಣಾಯಕ ವ್ಯತ್ಯಾಸವನ್ನು ಸ್ಪಷ್ಟಪಡಿಸುತ್ತೇವೆ ಮತ್ತು ಮೊದಲಿನಿಂದ ನಿಮ್ಮದೇ ಆದ ಕಸ್ಟಮ್ ಇಟರೇಟರ್ಗಳನ್ನು ನಿರ್ಮಿಸುವ ಮೂಲಕ ನಿಮಗೆ ಮಾರ್ಗದರ್ಶನ ನೀಡುತ್ತೇವೆ. ನೀವು ಪೈಥಾನ್ನ ಆಂತರಿಕ ಕಾರ್ಯವಿಧಾನಗಳ ಕುರಿತು ನಿಮ್ಮ ತಿಳುವಳಿಕೆಯನ್ನು ಆಳವಾಗಿಸಲು ಬಯಸುವ ಮಧ್ಯಂತರ ಡೆವಲಪರ್ ಆಗಿರಲಿ ಅಥವಾ ಹೆಚ್ಚು ಸಂಕೀರ್ಣ API ಗಳನ್ನು ವಿನ್ಯಾಸಗೊಳಿಸುವ ಗುರಿಯನ್ನು ಹೊಂದಿರುವ ಪರಿಣಿತರಾಗಿರಲಿ, ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಕರಗತ ಮಾಡಿಕೊಳ್ಳುವುದು ನಿಮ್ಮ ಪ್ರಯಾಣದಲ್ಲಿ ನಿರ್ಣಾಯಕ ಹಂತವಾಗಿದೆ.
'ಏಕೆ': ಇಟರೇಶನ್ನ ಮಹತ್ವ ಮತ್ತು ಶಕ್ತಿ
ನಾವು ತಾಂತ್ರಿಕ ಅನುಷ್ಠಾನಕ್ಕೆ ಧುಮುಕುವ ಮೊದಲು, ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ ಏಕೆ ಇಷ್ಟು ಮುಖ್ಯ ಎಂಬುದನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ಅತ್ಯಗತ್ಯ. ಇದರ ಪ್ರಯೋಜನಗಳು ಕೇವಲ `for` ಲೂಪ್ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುವುದಕ್ಕಿಂತಲೂ ಬಹಳಷ್ಟು ಮುಂದಿವೆ.
ಮೆಮೊರಿ ದಕ್ಷತೆ ಮತ್ತು ಲೇಜಿ ಎವಾಲ್ಯುಯೇಷನ್
ನೀವು ಹಲವಾರು ಗಿಗಾಬೈಟ್ಗಳಷ್ಟು ದೊಡ್ಡದಾದ ಲಾಗ್ ಫೈಲ್ ಅನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಬೇಕಾಗಿದೆ ಎಂದು ಊಹಿಸಿ. ನೀವು ಸಂಪೂರ್ಣ ಫೈಲ್ ಅನ್ನು ಮೆಮೊರಿಯಲ್ಲಿ ಪಟ್ಟಿಯಾಗಿ ಓದಿದರೆ, ನಿಮ್ಮ ಸಿಸ್ಟಂನ ಸಂಪನ್ಮೂಲಗಳನ್ನು ನೀವು ಖಂಡಿತವಾಗಿಯೂ ಖಾಲಿ ಮಾಡುತ್ತೀರಿ. ಲೇಜಿ ಎವಾಲ್ಯುಯೇಷನ್ ಎಂಬ ಪರಿಕಲ್ಪನೆಯ ಮೂಲಕ ಇಟರೇಟರ್ಗಳು ಈ ಸಮಸ್ಯೆಯನ್ನು ಸುಂದರವಾಗಿ ಪರಿಹರಿಸುತ್ತವೆ.
ಒಂದು ಇಟರೇಟರ್ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಒಮ್ಮೆಗೇ ಲೋಡ್ ಮಾಡುವುದಿಲ್ಲ. ಬದಲಾಗಿ, ಅದು ಒಂದು ಸಮಯದಲ್ಲಿ ಒಂದು ಐಟಂ ಅನ್ನು ಉತ್ಪಾದಿಸುತ್ತದೆ ಅಥವಾ ತರುತ್ತದೆ, ಅದು ವಿನಂತಿಸಿದಾಗ ಮಾತ್ರ. ಅದು ಅನುಕ್ರಮದಲ್ಲಿ ಎಲ್ಲಿದೆ ಎಂಬುದನ್ನು ನೆನಪಿಟ್ಟುಕೊಳ್ಳಲು ಆಂತರಿಕ ಸ್ಥಿತಿಯನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ. ಇದರರ್ಥ ನೀವು ಅನಂತವಾಗಿ ದೊಡ್ಡ ಡೇಟಾ ಸ್ಟ್ರೀಮ್ ಅನ್ನು (ಸಿದ್ಧಾಂತದಲ್ಲಿ) ಬಹಳ ಕಡಿಮೆ, ಸ್ಥಿರ ಪ್ರಮಾಣದ ಮೆಮೊರಿಯೊಂದಿಗೆ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಬಹುದು. ನಿಮ್ಮ ಪ್ರೋಗ್ರಾಂ ಕ್ರ್ಯಾಶ್ ಆಗದೆ ಬೃಹತ್ ಫೈಲ್ ಅನ್ನು ಸಾಲು-ಸಾಲು ಓದಲು ಅನುಮತಿಸುವ ಅದೇ ತತ್ವ ಇದು.
ಸ್ವಚ್ಛ, ಓದಬಹುದಾದ ಮತ್ತು ಸಾರ್ವತ್ರಿಕ ಕೋಡ್
ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ ಅನುಕ್ರಮ ಪ್ರವೇಶಕ್ಕಾಗಿ ಸಾರ್ವತ್ರಿಕ ಇಂಟರ್ಫೇಸ್ ಅನ್ನು ಒದಗಿಸುತ್ತದೆ. ಪಟ್ಟಿಗಳು, ಟುಪಲ್ಸ್, ಡಿಕ್ಷನರಿಗಳು, ಸ್ಟ್ರಿಂಗ್ಗಳು, ಫೈಲ್ ಆಬ್ಜೆಕ್ಟ್ಗಳು ಮತ್ತು ಇತರ ಹಲವು ಪ್ರಕಾರಗಳು ಈ ಪ್ರೋಟೋಕಾಲ್ಗೆ ಬದ್ಧವಾಗಿರುವುದರಿಂದ, ನೀವು ಎಲ್ಲವನ್ನೂ ಬಳಸಲು ಒಂದೇ ಸಿಂಟ್ಯಾಕ್ಸ್ ಅನ್ನು—`for` ಲೂಪ್—ಬಳಸಬಹುದು. ಈ ಏಕರೂಪತೆಯು ಪೈಥಾನ್ನ ಓದಬಲ್ಲಿಕೆಯ ಮೂಲಾಧಾರವಾಗಿದೆ.
ಈ ಕೋಡ್ ಅನ್ನು ಪರಿಗಣಿಸಿ:
ಕೋಡ್:
my_list = [1, 2, 3]
for item in my_list:
print(item)
my_string = "abc"
for char in my_string:
print(char)
with open('my_file.txt', 'r') as f:
for line in f:
print(line)
`for` ಲೂಪ್ ಇದು ಪೂರ್ಣಾಂಕಗಳ ಪಟ್ಟಿಯ ಮೇಲೆ, ಅಕ್ಷರಗಳ ಸ್ಟ್ರಿಂಗ್ ಮೇಲೆ, ಅಥವಾ ಫೈಲ್ನಿಂದ ಸಾಲುಗಳ ಮೇಲೆ ಇಟರೇಟ್ ಮಾಡುತ್ತಿದೆಯೇ ಎಂದು ಕಾಳಜಿ ವಹಿಸುವುದಿಲ್ಲ. ಇದು ಕೇವಲ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಅದರ ಇಟರೇಟರ್ಗಾಗಿ ಕೇಳುತ್ತದೆ ಮತ್ತು ನಂತರ ಇಟರೇಟರ್ ಅನ್ನು ಅದರ ಮುಂದಿನ ಐಟಂಗಾಗಿ ಪದೇ ಪದೇ ಕೇಳುತ್ತದೆ. ಈ ಅಬ್ಸ್ಟ್ರಕ್ಷನ್ ನಂಬಲಾಗದಷ್ಟು ಶಕ್ತಿಶಾಲಿಯಾಗಿದೆ.
ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ವಿಶ್ಲೇಷಿಸುವುದು
ಪ್ರೋಟೋಕಾಲ್ ಸ್ವತಃ ಆಶ್ಚರ್ಯಕರವಾಗಿ ಸರಳವಾಗಿದೆ, ಇದನ್ನು ಕೇವಲ ಎರಡು ವಿಶೇಷ ವಿಧಾನಗಳಿಂದ ವ್ಯಾಖ್ಯಾನಿಸಲಾಗಿದೆ, ಇದನ್ನು ಸಾಮಾನ್ಯವಾಗಿ "ಡಂಡರ್" (ಡಬಲ್ ಅಂಡರ್ಸ್ಕೋರ್) ವಿಧಾನಗಳು ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ:
- `__iter__()`
- `__next__()`
ಇವುಗಳನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಗ್ರಹಿಸಲು, ನಾವು ಮೊದಲು ಎರಡು ಸಂಬಂಧಿತ ಆದರೆ ವಿಭಿನ್ನ ಪರಿಕಲ್ಪನೆಗಳ ನಡುವಿನ ವ್ಯತ್ಯಾಸವನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಬೇಕು: ಒಂದು ಇಟರಬಲ್ ಮತ್ತು ಒಂದು ಇಟರೇಟರ್.
ಇಟರಬಲ್ vs. ಇಟರೇಟರ್: ಒಂದು ನಿರ್ಣಾಯಕ ವ್ಯತ್ಯಾಸ
ಇದು ಹೊಸಬರಿಗೆ ಆಗಾಗ್ಗೆ ಗೊಂದಲದ ಸಂಗತಿಯಾಗಿದೆ, ಆದರೆ ವ್ಯತ್ಯಾಸವು ನಿರ್ಣಾಯಕವಾಗಿದೆ.
ಇಟರಬಲ್ ಎಂದರೇನು?
ಒಂದು ಇಟರಬಲ್ ಎಂದರೆ ಲೂಪ್ ಮಾಡಬಹುದಾದ ಯಾವುದೇ ಆಬ್ಜೆಕ್ಟ್. ಇದು ಅಂತರ್ನಿರ್ಮಿತ `iter()` ಕಾರ್ಯಕ್ಕೆ ನೀವು ಇಟರೇಟರ್ ಪಡೆಯಲು ಕಳುಹಿಸಬಹುದಾದ ಆಬ್ಜೆಕ್ಟ್ ಆಗಿದೆ. ತಾಂತ್ರಿಕವಾಗಿ, ಒಂದು ಆಬ್ಜೆಕ್ಟ್ `__iter__` ವಿಧಾನವನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಿದರೆ ಅದನ್ನು ಇಟರಬಲ್ ಎಂದು ಪರಿಗಣಿಸಲಾಗುತ್ತದೆ. ಅದರ `__iter__` ವಿಧಾನದ ಏಕೈಕ ಉದ್ದೇಶವೆಂದರೆ ಇಟರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಹಿಂತಿರುಗಿಸುವುದು.
ಅಂತರ್ನಿರ್ಮಿತ ಇಟರಬಲ್ಗಳ ಉದಾಹರಣೆಗಳು:
- ಪಟ್ಟಿಗಳು (`[1, 2, 3]`)
- ಟುಪಲ್ಸ್ (`(1, 2, 3)`)
- ಸ್ಟ್ರಿಂಗ್ಗಳು (`"hello"`)
- ಡಿಕ್ಷನರಿಗಳು (`{'a': 1, 'b': 2}` - ಕೀಗಳ ಮೇಲೆ ಇಟರೇಟ್ ಮಾಡುತ್ತದೆ)
- ಸೆಟ್ಗಳು (`{1, 2, 3}`)
- ಫೈಲ್ ಆಬ್ಜೆಕ್ಟ್ಗಳು
ನೀವು ಇಟರಬಲ್ ಅನ್ನು ಡೇಟಾದ ಕಂಟೇನರ್ ಅಥವಾ ಮೂಲವೆಂದು ಭಾವಿಸಬಹುದು. ಐಟಂಗಳನ್ನು ಹೇಗೆ ಉತ್ಪಾದಿಸಬೇಕೆಂದು ಅದಕ್ಕೆ ಸ್ವತಃ ತಿಳಿದಿಲ್ಲ, ಆದರೆ ಹಾಗೆ ಮಾಡಬಲ್ಲ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಹೇಗೆ ರಚಿಸಬೇಕೆಂದು ಅದಕ್ಕೆ ತಿಳಿದಿದೆ: ಇಟರೇಟರ್.
ಇಟರೇಟರ್ ಎಂದರೇನು?
ಒಂದು ಇಟರೇಟರ್ ಎಂದರೆ ಇಟರೇಶನ್ ಸಮಯದಲ್ಲಿ ಮೌಲ್ಯಗಳನ್ನು ಉತ್ಪಾದಿಸುವ ಕೆಲಸವನ್ನು ನಿಜವಾಗಿ ಮಾಡುವ ಆಬ್ಜೆಕ್ಟ್. ಇದು ಡೇಟಾ ಸ್ಟ್ರೀಮ್ ಅನ್ನು ಪ್ರತಿನಿಧಿಸುತ್ತದೆ. ಒಂದು ಇಟರೇಟರ್ ಎರಡು ವಿಧಾನಗಳನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಬೇಕು:
- `__iter__()`: ಈ ವಿಧಾನವು ಇಟರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಸ್ವತಃ (`self`) ಹಿಂತಿರುಗಿಸಬೇಕು. ಇಟರಬಲ್ಗಳನ್ನು ನಿರೀಕ್ಷಿಸಿದ ಕಡೆಗಳಲ್ಲಿ ಇಟರೇಟರ್ಗಳನ್ನು ಸಹ ಬಳಸಲು ಇದು ಅವಶ್ಯಕವಾಗಿದೆ, ಉದಾಹರಣೆಗೆ, `for` ಲೂಪ್ನಲ್ಲಿ.
- `__next__()`: ಈ ವಿಧಾನವು ಇಟರೇಟರ್ನ ಎಂಜಿನ್ ಆಗಿದೆ. ಇದು ಅನುಕ್ರಮದಲ್ಲಿ ಮುಂದಿನ ಐಟಂ ಅನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ಹಿಂತಿರುಗಿಸಲು ಹೆಚ್ಚಿನ ಐಟಂಗಳು ಇಲ್ಲದಿದ್ದಾಗ, ಅದು ಖಂಡಿತವಾಗಿ `StopIteration` ವಿನಾಯಿತಿಯನ್ನು ಎತ್ತಬೇಕು. ಈ ವಿನಾಯಿತಿ ದೋಷವಲ್ಲ; ಇಟರೇಶನ್ ಪೂರ್ಣಗೊಂಡಿದೆ ಎಂದು ಲೂಪಿಂಗ್ ರಚನೆಗೆ ಇದು ಪ್ರಮಾಣಿತ ಸಂಕೇತವಾಗಿದೆ.
ಇಟರೇಟರ್ನ ಪ್ರಮುಖ ಗುಣಲಕ್ಷಣಗಳು:
- ಇದು ಸ್ಥಿತಿಯನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ: ಒಂದು ಇಟರೇಟರ್ ಅನುಕ್ರಮದಲ್ಲಿ ಅದರ ಪ್ರಸ್ತುತ ಸ್ಥಾನವನ್ನು ನೆನಪಿಸಿಕೊಳ್ಳುತ್ತದೆ.
- ಇದು ಒಂದು ಸಮಯದಲ್ಲಿ ಒಂದು ಮೌಲ್ಯವನ್ನು ಉತ್ಪಾದಿಸುತ್ತದೆ: `__next__` ವಿಧಾನದ ಮೂಲಕ.
- ಇದು ಖಾಲಿಯಾಗಬಲ್ಲದು: ಒಮ್ಮೆ ಇಟರೇಟರ್ ಸಂಪೂರ್ಣವಾಗಿ ಸೇವಿಸಿದ ನಂತರ (ಅಂದರೆ, ಅದು `StopIteration` ಅನ್ನು ಎತ್ತಿದ ನಂತರ), ಅದು ಖಾಲಿಯಾಗುತ್ತದೆ. ನೀವು ಅದನ್ನು ಮರುಹೊಂದಿಸಲು ಅಥವಾ ಮರುಬಳಕೆ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಮತ್ತೆ ಇಟರೇಟ್ ಮಾಡಲು, ನೀವು ಮೂಲ ಇಟರಬಲ್ಗೆ ಹಿಂತಿರುಗಿ ಮತ್ತು ಅದರ ಮೇಲೆ ಮತ್ತೆ `iter()` ಅನ್ನು ಕರೆ ಮಾಡುವ ಮೂಲಕ ಹೊಸ ಇಟರೇಟರ್ ಅನ್ನು ಪಡೆಯಬೇಕು.
ನಮ್ಮ ಮೊದಲ ಕಸ್ಟಮ್ ಇಟರೇಟರ್ ಅನ್ನು ನಿರ್ಮಿಸುವುದು: ಹಂತ-ಹಂತದ ಮಾರ್ಗದರ್ಶಿ
ಸಿದ್ಧಾಂತವು ಉತ್ತಮವಾಗಿದೆ, ಆದರೆ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಉತ್ತಮ ಮಾರ್ಗವೆಂದರೆ ಅದನ್ನು ನೀವೇ ನಿರ್ಮಿಸುವುದು. ಒಂದು ನಿರ್ದಿಷ್ಟ ಸಂಖ್ಯೆಯಿಂದ ಮಿತಿಯವರೆಗೆ ಇಟರೇಟ್ ಮಾಡುವ ಕೌಂಟರ್ ಆಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವ ಸರಳ ವರ್ಗವನ್ನು ರಚಿಸೋಣ.
ಉದಾಹರಣೆ 1: ಒಂದು ಸರಳ ಕೌಂಟರ್ ವರ್ಗ
ನಾವು `CountUpTo` ಎಂಬ ವರ್ಗವನ್ನು ರಚಿಸುತ್ತೇವೆ. ನೀವು ಅದರ ಒಂದು ನಿದರ್ಶನವನ್ನು ರಚಿಸಿದಾಗ, ನೀವು ಗರಿಷ್ಠ ಸಂಖ್ಯೆಯನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸುತ್ತೀರಿ, ಮತ್ತು ನೀವು ಅದರ ಮೇಲೆ ಇಟರೇಟ್ ಮಾಡಿದಾಗ, ಅದು 1 ರಿಂದ ಆ ಗರಿಷ್ಠದವರೆಗೆ ಸಂಖ್ಯೆಗಳನ್ನು ನೀಡುತ್ತದೆ.
ಕೋಡ್:
class CountUpTo:
"""An iterator that counts from 1 up to a specified maximum number."""
def __init__(self, max_num):
print("Initializing the CountUpTo object...")
self.max_num = max_num
self.current = 0 # This will store the state
def __iter__(self):
print("__iter__ called, returning self...")
# This object is its own iterator, so we return self
return self
def __next__(self):
print("__next__ called...")
if self.current < self.max_num:
self.current += 1
return self.current
else:
# This is the crucial part: signal that we are done.
print("Raising StopIteration.")
raise StopIteration
# How to use it
print("Creating the counter object...")
counter = CountUpTo(3)
print("\\nStarting the for loop...")
for number in counter:
print(f"For loop received: {number}")
ಕೋಡ್ ವಿಶ್ಲೇಷಣೆ ಮತ್ತು ವಿವರಣೆ
`for` ಲೂಪ್ ಚಲಿಸುವಾಗ ಏನಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ವಿಶ್ಲೇಷಿಸೋಣ:
- ಆರಂಭಿಕೀಕರಣ: `counter = CountUpTo(3)` ನಮ್ಮ ವರ್ಗದ ನಿದರ್ಶನವನ್ನು ರಚಿಸುತ್ತದೆ. `__init__` ವಿಧಾನವು ಚಲಿಸುತ್ತದೆ, `self.max_num` ಅನ್ನು 3 ಕ್ಕೆ ಮತ್ತು `self.current` ಅನ್ನು 0 ಕ್ಕೆ ಹೊಂದಿಸುತ್ತದೆ. ನಮ್ಮ ಆಬ್ಜೆಕ್ಟ್ನ ಸ್ಥಿತಿ ಈಗ ಪ್ರಾರಂಭಗೊಂಡಿದೆ.
- ಲೂಪ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸುವುದು: `for number in counter:` ಸಾಲನ್ನು ತಲುಪಿದಾಗ, ಪೈಥಾನ್ ಆಂತರಿಕವಾಗಿ `iter(counter)` ಅನ್ನು ಕರೆಯುತ್ತದೆ.
- `__iter__` ಅನ್ನು ಕರೆಯಲಾಗುತ್ತದೆ: `iter(counter)` ಕರೆ ನಮ್ಮ `counter.__iter__()` ವಿಧಾನವನ್ನು ಆಹ್ವಾನಿಸುತ್ತದೆ. ನಮ್ಮ ಕೋಡ್ನಿಂದ ನೀವು ನೋಡುವಂತೆ, ಈ ವಿಧಾನವು ಕೇವಲ ಸಂದೇಶವನ್ನು ಮುದ್ರಿಸುತ್ತದೆ ಮತ್ತು `self` ಅನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ಇದು `for` ಲೂಪ್ಗೆ, "ನೀವು `__next__` ಅನ್ನು ಕರೆಯಬೇಕಾದ ಆಬ್ಜೆಕ್ಟ್ ನಾನು!" ಎಂದು ಹೇಳುತ್ತದೆ.
- ಲೂಪ್ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ: ಈಗ `for` ಲೂಪ್ ಸಿದ್ಧವಾಗಿದೆ. ಪ್ರತಿ ಇಟರೇಶನ್ನಲ್ಲಿ, ಅದು ಸ್ವೀಕರಿಸಿದ ಇಟರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ನ ಮೇಲೆ (ನಮ್ಮ `counter` ಆಬ್ಜೆಕ್ಟ್) `next()` ಅನ್ನು ಕರೆಯುತ್ತದೆ.
- ಮೊದಲ `__next__` ಕರೆ: `counter.__next__()` ವಿಧಾನವನ್ನು ಕರೆಯಲಾಗುತ್ತದೆ. `self.current` 0 ಆಗಿದೆ, ಇದು `self.max_num` (3) ಗಿಂತ ಕಡಿಮೆ ಇದೆ. ಕೋಡ್ `self.current` ಅನ್ನು 1 ಕ್ಕೆ ಹೆಚ್ಚಿಸುತ್ತದೆ ಮತ್ತು ಅದನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. `for` ಲೂಪ್ ಈ ಮೌಲ್ಯವನ್ನು `number` ವೇರಿಯೇಬಲ್ಗೆ ನಿಯೋಜಿಸುತ್ತದೆ, ಮತ್ತು ಲೂಪ್ ಬಾಡಿ (`print(...)`) ಕಾರ್ಯಗತಗೊಳ್ಳುತ್ತದೆ.
- ಎರಡನೇ `__next__` ಕರೆ: ಲೂಪ್ ಮುಂದುವರಿಯುತ್ತದೆ. `__next__` ಅನ್ನು ಮತ್ತೆ ಕರೆಯಲಾಗುತ್ತದೆ. `self.current` 1 ಆಗಿದೆ. ಇದನ್ನು 2 ಕ್ಕೆ ಹೆಚ್ಚಿಸಿ ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ.
- ಮೂರನೇ `__next__` ಕರೆ: `__next__` ಅನ್ನು ಮತ್ತೆ ಕರೆಯಲಾಗುತ್ತದೆ. `self.current` 2 ಆಗಿದೆ. ಇದನ್ನು 3 ಕ್ಕೆ ಹೆಚ್ಚಿಸಿ ಹಿಂತಿರುಗಿಸಲಾಗುತ್ತದೆ.
- ಅಂತಿಮ `__next__` ಕರೆ: `__next__` ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಕರೆಯಲಾಗುತ್ತದೆ. ಈಗ, `self.current` 3 ಆಗಿದೆ. `self.current < self.max_num` ಎಂಬ ಸ್ಥಿತಿ ತಪ್ಪು. `else` ಬ್ಲಾಕ್ ಕಾರ್ಯಗತಗೊಳ್ಳುತ್ತದೆ, ಮತ್ತು `StopIteration` ಅನ್ನು ಎತ್ತಲಾಗುತ್ತದೆ.
- ಲೂಪ್ ಅನ್ನು ಕೊನೆಗೊಳಿಸುವುದು: `for` ಲೂಪ್ `StopIteration` ವಿನಾಯಿತಿಯನ್ನು ಹಿಡಿಯಲು ವಿನ್ಯಾಸಗೊಳಿಸಲಾಗಿದೆ. ಅದು ಹಾಗೆ ಮಾಡಿದಾಗ, ಇಟರೇಶನ್ ಮುಗಿದಿದೆ ಎಂದು ಅದಕ್ಕೆ ತಿಳಿದಿರುತ್ತದೆ ಮತ್ತು ಅದು ಸಲೀಸಾಗಿ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ. ಪ್ರೋಗ್ರಾಂ ಲೂಪ್ ನಂತರದ ಯಾವುದೇ ಕೋಡ್ ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವುದನ್ನು ಮುಂದುವರಿಸುತ್ತದೆ.
ಒಂದು ಪ್ರಮುಖ ವಿವರವನ್ನು ಗಮನಿಸಿ: ನೀವು ಅದೇ `counter` ಆಬ್ಜೆಕ್ಟ್ ಮೇಲೆ `for` ಲೂಪ್ ಅನ್ನು ಮತ್ತೆ ಚಲಾಯಿಸಲು ಪ್ರಯತ್ನಿಸಿದರೆ, ಅದು ಕೆಲಸ ಮಾಡುವುದಿಲ್ಲ. ಇಟರೇಟರ್ ಖಾಲಿಯಾಗಿದೆ. `self.current` ಈಗಾಗಲೇ 3 ಆಗಿದೆ, ಆದ್ದರಿಂದ ಯಾವುದೇ ಮುಂದಿನ `__next__` ಕರೆಗಳು ತಕ್ಷಣವೇ `StopIteration` ಅನ್ನು ಎತ್ತುತ್ತವೆ. ನಮ್ಮ ಆಬ್ಜೆಕ್ಟ್ ತನ್ನದೇ ಆದ ಇಟರೇಟರ್ ಆಗಿರುವ ಪರಿಣಾಮ ಇದು.
ಸುಧಾರಿತ ಇಟರೇಟರ್ ಪರಿಕಲ್ಪನೆಗಳು ಮತ್ತು ನೈಜ-ಪ್ರಪಂಚದ ಅಪ್ಲಿಕೇಶನ್ಗಳು
ಸರಳ ಕೌಂಟರ್ಗಳು ಕಲಿಯಲು ಉತ್ತಮ ಮಾರ್ಗವಾಗಿದೆ, ಆದರೆ ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ನ ನಿಜವಾದ ಶಕ್ತಿಯು ಹೆಚ್ಚು ಸಂಕೀರ್ಣ, ಕಸ್ಟಮ್ ಡೇಟಾ ರಚನೆಗಳಿಗೆ ಅನ್ವಯಿಸಿದಾಗ ಹೊಳೆಯುತ್ತದೆ.
ಇಟರಬಲ್ ಮತ್ತು ಇಟರೇಟರ್ ಅನ್ನು ಸಂಯೋಜಿಸುವುದರೊಂದಿಗೆ ಇರುವ ಸಮಸ್ಯೆ
ನಮ್ಮ `CountUpTo` ಉದಾಹರಣೆಯಲ್ಲಿ, ವರ್ಗವು ಇಟರಬಲ್ ಮತ್ತು ಇಟರೇಟರ್ ಎರಡೂ ಆಗಿತ್ತು. ಇದು ಸರಳವಾಗಿದೆ ಆದರೆ ಒಂದು ದೊಡ್ಡ ನ್ಯೂನತೆಯನ್ನು ಹೊಂದಿದೆ: ಫಲಿತಾಂಶದ ಇಟರೇಟರ್ ಖಾಲಿಯಾಗುತ್ತದೆ. ಒಮ್ಮೆ ನೀವು ಅದರ ಮೇಲೆ ಲೂಪ್ ಮಾಡಿದರೆ, ಅದು ಮುಗಿಯುತ್ತದೆ.
ಕೋಡ್:
counter = CountUpTo(2)
print("First iteration:")
for num in counter: print(num) # Works fine
print("\\nSecond iteration:")
for num in counter: print(num) # Prints nothing!
ಇದು ಸಂಭವಿಸುತ್ತದೆ ಏಕೆಂದರೆ ಸ್ಥಿತಿ (`self.current`) ಆಬ್ಜೆಕ್ಟ್ನಲ್ಲಿಯೇ ಸಂಗ್ರಹಿಸಲ್ಪಡುತ್ತದೆ. ಮೊದಲ ಲೂಪ್ ನಂತರ, `self.current` 2 ಆಗಿದೆ, ಮತ್ತು ಯಾವುದೇ ಮುಂದಿನ `__next__` ಕರೆಗಳು `StopIteration` ಅನ್ನು ಮಾತ್ರ ಎತ್ತುತ್ತವೆ. ಈ ವರ್ತನೆಯು ಪ್ರಮಾಣಿತ ಪೈಥಾನ್ ಪಟ್ಟಿಯಿಂದ ಭಿನ್ನವಾಗಿದೆ, ಇದನ್ನು ನೀವು ಅನೇಕ ಬಾರಿ ಇಟರೇಟ್ ಮಾಡಬಹುದು.
ಹೆಚ್ಚು ದೃಢವಾದ ಮಾದರಿ: ಇಟರಬಲ್ ಅನ್ನು ಇಟರೇಟರ್ನಿಂದ ಬೇರ್ಪಡಿಸುವುದು
ಪೈಥಾನ್ನ ಅಂತರ್ನಿರ್ಮಿತ ಸಂಗ್ರಹಗಳಂತಹ ಮರುಬಳಕೆ ಮಾಡಬಹುದಾದ ಇಟರಬಲ್ಗಳನ್ನು ರಚಿಸಲು, ಎರಡು ಪಾತ್ರಗಳನ್ನು ಬೇರ್ಪಡಿಸುವುದು ಉತ್ತಮ ಅಭ್ಯಾಸವಾಗಿದೆ. ಕಂಟೇನರ್ ಆಬ್ಜೆಕ್ಟ್ ಇಟರಬಲ್ ಆಗಿರುತ್ತದೆ, ಮತ್ತು ಅದರ `__iter__` ವಿಧಾನವನ್ನು ಪ್ರತಿ ಬಾರಿ ಕರೆದಾಗ ಅದು ಹೊಸ, ತಾಜಾ ಇಟರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಉತ್ಪಾದಿಸುತ್ತದೆ.
ನಮ್ಮ ಉದಾಹರಣೆಯನ್ನು ಎರಡು ವರ್ಗಗಳಾಗಿ ಮರುರೂಪಿಸೋಣ: `Sentence` (ಇಟರಬಲ್) ಮತ್ತು `SentenceIterator` (ಇಟರೇಟರ್).
ಕೋಡ್:
class SentenceIterator:
"""The iterator responsible for state and producing values."""
def __init__(self, words):
self.words = words
self.index = 0
def __next__(self):
try:
word = self.words[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return word
def __iter__(self):
# An iterator must also be an iterable, returning itself.
return self
class Sentence:
"""The iterable container class."""
def __init__(self, text):
# The container holds the data.
self.words = text.split()
def __iter__(self):
# Each time __iter__ is called, it creates a NEW iterator object.
return SentenceIterator(self.words)
# How to use it
my_sentence = Sentence('This is a test')
print("First iteration:")
for word in my_sentence:
print(word)
print("\\nSecond iteration:")
for word in my_sentence:
print(word)
ಈಗ, ಇದು ನಿಖರವಾಗಿ ಪಟ್ಟಿಯಂತೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ! ಪ್ರತಿ ಬಾರಿ `for` ಲೂಪ್ ಪ್ರಾರಂಭವಾದಾಗ, ಅದು `my_sentence.__iter__()` ಅನ್ನು ಕರೆಯುತ್ತದೆ, ಇದು ತನ್ನದೇ ಆದ ಸ್ಥಿತಿಯೊಂದಿಗೆ (`self.index = 0`) ಹೊಸ `SentenceIterator` ನಿದರ್ಶನವನ್ನು ರಚಿಸುತ್ತದೆ. ಇದು ಒಂದೇ `Sentence` ಆಬ್ಜೆಕ್ಟ್ ಮೇಲೆ ಬಹು, ಸ್ವತಂತ್ರ ಇಟರೇಶನ್ಗಳಿಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಈ ಮಾದರಿಯು ಹೆಚ್ಚು ದೃಢವಾಗಿದೆ ಮತ್ತು ಪೈಥಾನ್ನ ಸ್ವಂತ ಸಂಗ್ರಹಗಳನ್ನು ಹೇಗೆ ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುತ್ತದೆ ಎಂಬುದಕ್ಕೆ ಇದು ಉದಾಹರಣೆಯಾಗಿದೆ.
ಉದಾಹರಣೆ: ಅನಂತ ಇಟರೇಟರ್ಗಳು
ಇಟರೇಟರ್ಗಳು ಸೀಮಿತವಾಗಿರಬೇಕಾಗಿಲ್ಲ. ಅವು ಅಂತ್ಯವಿಲ್ಲದ ಡೇಟಾ ಅನುಕ್ರಮವನ್ನು ಪ್ರತಿನಿಧಿಸಬಹುದು. ಇಲ್ಲಿ ಅವುಗಳ ಲೇಜಿ, ಒಂದು ಸಮಯದಲ್ಲಿ-ಒಂದು ಸ್ವಭಾವವು ಒಂದು ದೊಡ್ಡ ಪ್ರಯೋಜನವಾಗಿದೆ. ಫಿಬೊನಾಚಿ ಸಂಖ್ಯೆಗಳ ಅನಂತ ಅನುಕ್ರಮಕ್ಕಾಗಿ ಒಂದು ಇಟರೇಟರ್ ಅನ್ನು ರಚಿಸೋಣ.
ಕೋಡ್:
class FibonacciIterator:
"""Generates an infinite sequence of Fibonacci numbers."""
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
result = self.a
self.a, self.b = self.b, self.a + self.b
return result
# How to use it - CAUTION: Infinite loop without a break!
fib_gen = FibonacciIterator()
for i, num in enumerate(fib_gen):
print(f"Fibonacci({i}): {num}")
if i >= 10: # We must provide a stopping condition
break
ಈ ಇಟರೇಟರ್ ತನ್ನಷ್ಟಕ್ಕೆ ತಾನೇ `StopIteration` ಅನ್ನು ಎಂದಿಗೂ ಎತ್ತುವುದಿಲ್ಲ. ಲೂಪ್ ಅನ್ನು ಅಂತ್ಯಗೊಳಿಸಲು ಒಂದು ಸ್ಥಿತಿಯನ್ನು (`break` ಹೇಳಿಕೆಯಂತಹ) ಒದಗಿಸುವುದು ಕರೆ ಮಾಡುವ ಕೋಡ್ನ ಜವಾಬ್ದಾರಿಯಾಗಿದೆ. ಡೇಟಾ ಸ್ಟ್ರೀಮಿಂಗ್, ಈವೆಂಟ್ ಲೂಪ್ಗಳು ಮತ್ತು ಸಂಖ್ಯಾತ್ಮಕ ಸಿಮ್ಯುಲೇಶನ್ಗಳಲ್ಲಿ ಈ ಮಾದರಿ ಸಾಮಾನ್ಯವಾಗಿದೆ.
ಪೈಥಾನ್ ಪರಿಸರ ವ್ಯವಸ್ಥೆಯಲ್ಲಿ ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್
`__iter__` ಮತ್ತು `__next__` ಅನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ಪೈಥಾನ್ನಲ್ಲಿ ಎಲ್ಲೆಡೆ ಅವುಗಳ ಪ್ರಭಾವವನ್ನು ನೋಡಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ಪೈಥಾನ್ನ ಅನೇಕ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸುಗಮವಾಗಿ ಒಟ್ಟಾಗಿ ಕೆಲಸ ಮಾಡುವಂತೆ ಮಾಡುವ ಏಕೀಕೃತ ಪ್ರೋಟೋಕಾಲ್ ಆಗಿದೆ.
`for` ಲೂಪ್ಗಳು *ನಿಜವಾಗಿ* ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ
ನಾವು ಇದನ್ನು ಅಪ್ರಜ್ಞಾಪೂರ್ವಕವಾಗಿ ಚರ್ಚಿಸಿದ್ದೇವೆ, ಆದರೆ ಅದನ್ನು ಸ್ಪಷ್ಟಪಡಿಸೋಣ. ಪೈಥಾನ್ ಈ ಸಾಲನ್ನು ಎದುರಿಸಿದಾಗ:
`for item in my_iterable:`
ಇದು ತೆರೆಯ ಹಿಂದಿನ ಈ ಕೆಳಗಿನ ಹಂತಗಳನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ:
- ಇಟರೇಟರ್ ಪಡೆಯಲು `iter(my_iterable)` ಅನ್ನು ಕರೆಯುತ್ತದೆ. ಇದು, ಪ್ರತಿಯಾಗಿ, `my_iterable.__iter__()` ಅನ್ನು ಕರೆಯುತ್ತದೆ. ಹಿಂತಿರುಗಿದ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು `iterator_obj` ಎಂದು ಕರೆಯೋಣ.
- ಇದು ಅನಂತ `while True` ಲೂಪ್ ಅನ್ನು ಪ್ರವೇಶಿಸುತ್ತದೆ.
- ಲೂಪ್ ಒಳಗೆ, ಇದು `next(iterator_obj)` ಅನ್ನು ಕರೆಯುತ್ತದೆ, ಇದು ಪ್ರತಿಯಾಗಿ `iterator_obj.__next__()` ಅನ್ನು ಕರೆಯುತ್ತದೆ.
- `__next__` ಒಂದು ಮೌಲ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸಿದರೆ, ಅದನ್ನು `item` ವೇರಿಯೇಬಲ್ಗೆ ನಿಯೋಜಿಸಲಾಗುತ್ತದೆ, ಮತ್ತು `for` ಲೂಪ್ ಬ್ಲಾಕ್ನೊಳಗಿನ ಕೋಡ್ ಕಾರ್ಯಗತಗೊಳ್ಳುತ್ತದೆ.
- `__next__` ಒಂದು `StopIteration` ವಿನಾಯಿತಿಯನ್ನು ಎತ್ತಿದರೆ, `for` ಲೂಪ್ ಈ ವಿನಾಯಿತಿಯನ್ನು ಹಿಡಿದು ಅದರ ಆಂತರಿಕ `while` ಲೂಪ್ನಿಂದ ಹೊರಬರುತ್ತದೆ. ಇಟರೇಶನ್ ಪೂರ್ಣಗೊಂಡಿದೆ.
ಕಾಂಪ್ರಹೆನ್ಷನ್ಗಳು ಮತ್ತು ಜನರೇಟರ್ ಅಭಿವ್ಯಕ್ತಿಗಳು
ಪಟ್ಟಿ, ಸೆಟ್ ಮತ್ತು ಡಿಕ್ಷನರಿ ಕಾಂಪ್ರಹೆನ್ಷನ್ಗಳು ಎಲ್ಲವೂ ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ನಿಂದ ಚಾಲಿತವಾಗಿವೆ. ನೀವು ಬರೆಯುವಾಗ:
`squares = [x * x for x in range(10)]`
ಪೈಥಾನ್ ಪರಿಣಾಮಕಾರಿಯಾಗಿ `range(10)` ಆಬ್ಜೆಕ್ಟ್ ಮೇಲೆ ಇಟರೇಶನ್ ಅನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ, ಪ್ರತಿ ಮೌಲ್ಯವನ್ನು ಪಡೆಯುತ್ತದೆ ಮತ್ತು ಪಟ್ಟಿಯನ್ನು ನಿರ್ಮಿಸಲು `x * x` ಅಭಿವ್ಯಕ್ತಿಯನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುತ್ತದೆ. ಲೇಜಿ ಇಟರೇಶನ್ನ ಇನ್ನೂ ಹೆಚ್ಚು ನೇರ ಬಳಕೆಯಾಗಿರುವ ಜನರೇಟರ್ ಅಭಿವ್ಯಕ್ತಿಗಳಿಗೂ ಇದು ಅನ್ವಯಿಸುತ್ತದೆ:
`lazy_squares = (x * x for x in range(1000000))`
ಇದು ಮೆಮೊರಿಯಲ್ಲಿ ಒಂದು ಮಿಲಿಯನ್ ಐಟಂಗಳ ಪಟ್ಟಿಯನ್ನು ರಚಿಸುವುದಿಲ್ಲ. ಇದು ಒಂದು ಇಟರೇಟರ್ ಅನ್ನು (ನಿರ್ದಿಷ್ಟವಾಗಿ, ಜನರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್) ರಚಿಸುತ್ತದೆ, ಅದು ನೀವು ಅದರ ಮೇಲೆ ಇಟರೇಟ್ ಮಾಡಿದಂತೆ ಒಂದೊಂದಾಗಿ ವರ್ಗಗಳನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುತ್ತದೆ.
ಜನರೇಟರ್ಗಳು: ಇಟರೇಟರ್ಗಳನ್ನು ರಚಿಸಲು ಸರಳವಾದ ಮಾರ್ಗ
`__iter__` ಮತ್ತು `__next__` ನೊಂದಿಗೆ ಪೂರ್ಣ ವರ್ಗವನ್ನು ರಚಿಸುವುದು ನಿಮಗೆ ಗರಿಷ್ಠ ನಿಯಂತ್ರಣವನ್ನು ನೀಡುತ್ತದೆ, ಆದರೆ ಸರಳ ಸಂದರ್ಭಗಳಲ್ಲಿ ಇದು ವಿವರವಾಗಿರುತ್ತದೆ. ಪೈಥಾನ್ ಇಟರೇಟರ್ಗಳನ್ನು ರಚಿಸಲು ಹೆಚ್ಚು ಸಂಕ್ಷಿಪ್ತ ಸಿಂಟ್ಯಾಕ್ಸ್ ಅನ್ನು ಒದಗಿಸುತ್ತದೆ: ಜನರೇಟರ್ಗಳು.
ಜನರೇಟರ್ ಎಂದರೆ `yield` ಕೀವರ್ಡ್ ಅನ್ನು ಬಳಸುವ ಒಂದು ಕಾರ್ಯ. ನೀವು ಜನರೇಟರ್ ಕಾರ್ಯವನ್ನು ಕರೆದಾಗ, ಅದು ಕೋಡ್ ಅನ್ನು ಚಲಾಯಿಸುವುದಿಲ್ಲ. ಬದಲಾಗಿ, ಇದು ಜನರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ, ಇದು ಪೂರ್ಣ ಪ್ರಮಾಣದ ಇಟರೇಟರ್ ಆಗಿದೆ.
ನಮ್ಮ `CountUpTo` ಉದಾಹರಣೆಯನ್ನು ಜನರೇಟರ್ ಆಗಿ ಮರುಬರೆಯೋಣ:
ಕೋಡ್:
def count_up_to_generator(max_num):
"""A generator function that yields numbers from 1 to max_num."""
print("Generator started...")
current = 1
while current <= max_num:
yield current # Pauses here and sends a value back
current += 1
print("Generator finished.")
# How to use it
counter_gen = count_up_to_generator(3)
for number in counter_gen:
print(f"For loop received: {number}")
ಇದು ಎಷ್ಟು ಸರಳವಾಗಿದೆ ನೋಡಿ! ಇಲ್ಲಿ `yield` ಕೀವರ್ಡ್ ಮ್ಯಾಜಿಕ್ ಆಗಿದೆ. `yield` ಎದುರಾದಾಗ, ಕಾರ್ಯದ ಸ್ಥಿತಿಯನ್ನು ಸ್ಥಗಿತಗೊಳಿಸಲಾಗುತ್ತದೆ, ಮೌಲ್ಯವನ್ನು ಕರೆ ಮಾಡುವವರಿಗೆ ಕಳುಹಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ಕಾರ್ಯವು ವಿರಾಮಗೊಳ್ಳುತ್ತದೆ. ಜನರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ ಮೇಲೆ ಮುಂದಿನ ಬಾರಿ `__next__` ಅನ್ನು ಕರೆದಾಗ, ಕಾರ್ಯವು ನಿಲ್ಲಿಸಿದ ಸ್ಥಳದಿಂದಲೇ ಕಾರ್ಯಗತಗೊಳಿಸುವುದನ್ನು ಪುನರಾರಂಭಿಸುತ್ತದೆ, ಅದು ಮತ್ತೊಂದು `yield` ಅನ್ನು ತಲುಪುವವರೆಗೆ ಅಥವಾ ಕಾರ್ಯವು ಮುಗಿಯುವವರೆಗೆ. ಕಾರ್ಯವು ಮುಗಿದಾಗ, ನಿಮಗಾಗಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ `StopIteration` ಅನ್ನು ಎತ್ತಲಾಗುತ್ತದೆ.
ತೆರೆಯ ಹಿಂದಿನ ಕಾರ್ಯವೈಖರಿಯಲ್ಲಿ, ಪೈಥಾನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ `__iter__` ಮತ್ತು `__next__` ವಿಧಾನಗಳೊಂದಿಗೆ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ರಚಿಸಿದೆ. ಜನರೇಟರ್ಗಳು ಹೆಚ್ಚಾಗಿ ಹೆಚ್ಚು ಪ್ರಾಯೋಗಿಕ ಆಯ್ಕೆಯಾಗಿದ್ದರೂ, ಡೀಬಗ್ ಮಾಡುವಿಕೆ, ಸಂಕೀರ್ಣ ವ್ಯವಸ್ಥೆಗಳನ್ನು ವಿನ್ಯಾಸಗೊಳಿಸುವುದು ಮತ್ತು ಪೈಥಾನ್ನ ಮೂಲ ಯಂತ್ರಶಾಸ್ತ್ರವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಆಧಾರವಾಗಿರುವ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ಅತ್ಯಗತ್ಯ.
ಉತ್ತಮ ಅಭ್ಯಾಸಗಳು ಮತ್ತು ಸಾಮಾನ್ಯ ತಪ್ಪುಗಳು
ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವಾಗ, ಸಾಮಾನ್ಯ ದೋಷಗಳನ್ನು ತಪ್ಪಿಸಲು ಈ ಮಾರ್ಗಸೂಚಿಗಳನ್ನು ನೆನಪಿನಲ್ಲಿಡಿ.
ಉತ್ತಮ ಅಭ್ಯಾಸಗಳು
- ಇಟರಬಲ್ ಮತ್ತು ಇಟರೇಟರ್ ಅನ್ನು ಬೇರ್ಪಡಿಸಿ: ಅನೇಕ ಟ್ರಾವರ್ಸಲ್ಗಳನ್ನು ಬೆಂಬಲಿಸಬೇಕಾದ ಯಾವುದೇ ಕಂಟೇನರ್ ಆಬ್ಜೆಕ್ಟ್ಗಾಗಿ, ಯಾವಾಗಲೂ ಇಟರೇಟರ್ ಅನ್ನು ಪ್ರತ್ಯೇಕ ವರ್ಗದಲ್ಲಿ ಕಾರ್ಯಗತಗೊಳಿಸಿ. ಕಂಟೇನರ್ನ `__iter__` ವಿಧಾನವು ಪ್ರತಿ ಬಾರಿ ಇಟರೇಟರ್ ವರ್ಗದ ಹೊಸ ನಿದರ್ಶನವನ್ನು ಹಿಂತಿರುಗಿಸಬೇಕು.
- ಯಾವಾಗಲೂ `StopIteration` ಅನ್ನು ಎತ್ತಿ: `__next__` ವಿಧಾನವು ಅಂತ್ಯವನ್ನು ಸಂಕೇತಿಸಲು ವಿಶ್ವಾಸಾರ್ಹವಾಗಿ `StopIteration` ಅನ್ನು ಎತ್ತಬೇಕು. ಇದನ್ನು ಮರೆತರೆ ಅನಂತ ಲೂಪ್ಗಳಿಗೆ ಕಾರಣವಾಗುತ್ತದೆ.
- ಇಟರೇಟರ್ಗಳು ಇಟರಬಲ್ ಆಗಿರಬೇಕು: ಇಟರೇಟರ್ನ `__iter__` ವಿಧಾನವು ಯಾವಾಗಲೂ `self` ಅನ್ನು ಹಿಂತಿರುಗಿಸಬೇಕು. ಇದು ಇಟರಬಲ್ ಅನ್ನು ನಿರೀಕ್ಷಿಸಿದ ಯಾವುದೇ ಸ್ಥಳದಲ್ಲಿ ಇಟರೇಟರ್ ಅನ್ನು ಬಳಸಲು ಅನುಮತಿಸುತ್ತದೆ.
- ಸರಳತೆಗಾಗಿ ಜನರೇಟರ್ಗಳನ್ನು ಆದ್ಯತೆ ನೀಡಿ: ನಿಮ್ಮ ಇಟರೇಟರ್ ತರ್ಕವು ಸರಳವಾಗಿದ್ದರೆ ಮತ್ತು ಒಂದೇ ಕಾರ್ಯವಾಗಿ ವ್ಯಕ್ತಪಡಿಸಬಹುದಾದರೆ, ಜನರೇಟರ್ ಯಾವಾಗಲೂ ಸ್ವಚ್ಛ ಮತ್ತು ಹೆಚ್ಚು ಓದಬಲ್ಲವಾಗಿರುತ್ತದೆ. ಇಟರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ನೊಂದಿಗೆ ಹೆಚ್ಚು ಸಂಕೀರ್ಣ ಸ್ಥಿತಿ ಅಥವಾ ವಿಧಾನಗಳನ್ನು ಸಂಯೋಜಿಸಲು ನಿಮಗೆ ಅಗತ್ಯವಿದ್ದಾಗ ಪೂರ್ಣ ಇಟರೇಟರ್ ವರ್ಗವನ್ನು ಬಳಸಿ.
ಸಾಮಾನ್ಯ ತಪ್ಪುಗಳು
- ಖಾಲಿಯಾಗಬಲ್ಲ ಇಟರೇಟರ್ ಸಮಸ್ಯೆ: ಚರ್ಚಿಸಿದಂತೆ, ಒಂದು ಆಬ್ಜೆಕ್ಟ್ ತನ್ನದೇ ಆದ ಇಟರೇಟರ್ ಆಗಿರುವಾಗ, ಅದನ್ನು ಒಮ್ಮೆ ಮಾತ್ರ ಬಳಸಬಹುದು ಎಂಬುದನ್ನು ನೆನಪಿನಲ್ಲಿಡಿ. ನೀವು ಅನೇಕ ಬಾರಿ ಇಟರೇಟ್ ಮಾಡಬೇಕಾದರೆ, ನೀವು ಹೊಸ ನಿದರ್ಶನವನ್ನು ರಚಿಸಬೇಕು ಅಥವಾ ಬೇರ್ಪಡಿಸಿದ ಇಟರಬಲ್/ಇಟರೇಟರ್ ಮಾದರಿಯನ್ನು ಬಳಸಬೇಕು.
- ಸ್ಥಿತಿಯನ್ನು ಮರೆಯುವುದು: `__next__` ವಿಧಾನವು ಇಟರೇಟರ್ನ ಆಂತರಿಕ ಸ್ಥಿತಿಯನ್ನು ಮಾರ್ಪಡಿಸಬೇಕು (ಉದಾಹರಣೆಗೆ, ಸೂಚ್ಯಂಕವನ್ನು ಹೆಚ್ಚಿಸುವುದು ಅಥವಾ ಪಾಯಿಂಟರ್ ಅನ್ನು ಮುನ್ನಡೆಸುವುದು). ಸ್ಥಿತಿಯನ್ನು ನವೀಕರಿಸದಿದ್ದರೆ, `__next__` ಒಂದೇ ಮೌಲ್ಯವನ್ನು ಪದೇ ಪದೇ ಹಿಂತಿರುಗಿಸುತ್ತದೆ, ಇದು ಅನಂತ ಲೂಪ್ಗೆ ಕಾರಣವಾಗಬಹುದು.
- ಇಟರೇಟ್ ಮಾಡುವಾಗ ಸಂಗ್ರಹವನ್ನು ಮಾರ್ಪಡಿಸುವುದು: ಸಂಗ್ರಹದ ಮೇಲೆ ಇಟರೇಟ್ ಮಾಡುವಾಗ ಅದನ್ನು ಮಾರ್ಪಡಿಸುವುದು (ಉದಾಹರಣೆಗೆ, ಲೂಪ್ ಆಗುತ್ತಿರುವ `for` ಲೂಪ್ ಒಳಗೆ ಪಟ್ಟಿಯಿಂದ ಐಟಂಗಳನ್ನು ತೆಗೆದುಹಾಕುವುದು) ಅನಿರೀಕ್ಷಿತ ವರ್ತನೆಗೆ ಕಾರಣವಾಗಬಹುದು, ಉದಾಹರಣೆಗೆ ಐಟಂಗಳನ್ನು ಬಿಟ್ಟುಬಿಡುವುದು ಅಥವಾ ಅನಿರೀಕ್ಷಿತ ದೋಷಗಳನ್ನು ಎತ್ತುವುದು. ನೀವು ಮೂಲವನ್ನು ಮಾರ್ಪಡಿಸಬೇಕಾದರೆ ಸಂಗ್ರಹದ ನಕಲಿನಲ್ಲಿ ಇಟರೇಟ್ ಮಾಡುವುದು ಸಾಮಾನ್ಯವಾಗಿ ಸುರಕ್ಷಿತವಾಗಿದೆ.
ತೀರ್ಮಾನ
ಇಟರೇಟರ್ ಪ್ರೋಟೋಕಾಲ್, ಅದರ ಸರಳ `__iter__` ಮತ್ತು `__next__` ವಿಧಾನಗಳೊಂದಿಗೆ, ಪೈಥಾನ್ನಲ್ಲಿನ ಇಟರೇಶನ್ನ ಅಡಿಪಾಯವಾಗಿದೆ. ಇದು ಭಾಷೆಯ ವಿನ್ಯಾಸ ತತ್ವಶಾಸ್ತ್ರಕ್ಕೆ ಒಂದು ಪುರಾವೆಯಾಗಿದೆ: ಶಕ್ತಿಶಾಲಿ ಮತ್ತು ಸಂಕೀರ್ಣ ನಡವಳಿಕೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುವ ಸರಳ, ಸ್ಥಿರ ಇಂಟರ್ಫೇಸ್ಗಳಿಗೆ ಒಲವು. ಅನುಕ್ರಮ ಡೇಟಾ ಪ್ರವೇಶಕ್ಕಾಗಿ ಸಾರ್ವತ್ರಿಕ ಒಪ್ಪಂದವನ್ನು ಒದಗಿಸುವ ಮೂಲಕ, ಪ್ರೋಟೋಕಾಲ್ `for` ಲೂಪ್ಗಳು, ಕಾಂಪ್ರಹೆನ್ಷನ್ಗಳು ಮತ್ತು ಅಸಂಖ್ಯಾತ ಇತರ ಪರಿಕರಗಳನ್ನು ಅದರ ಭಾಷೆಯನ್ನು ಮಾತನಾಡಲು ಆಯ್ಕೆ ಮಾಡುವ ಯಾವುದೇ ಆಬ್ಜೆಕ್ಟ್ನೊಂದಿಗೆ ಸುಗಮವಾಗಿ ಕೆಲಸ ಮಾಡಲು ಅನುಮತಿಸುತ್ತದೆ.
ಈ ಪ್ರೋಟೋಕಾಲ್ ಅನ್ನು ಕರಗತ ಮಾಡಿಕೊಳ್ಳುವ ಮೂಲಕ, ನೀವು ಪೈಥಾನ್ ಪರಿಸರ ವ್ಯವಸ್ಥೆಯಲ್ಲಿ ಪ್ರಥಮ ದರ್ಜೆ ನಾಗರಿಕರಾಗಿರುವ ನಿಮ್ಮದೇ ಆದ ಅನುಕ್ರಮ-ರೀತಿಯ ಆಬ್ಜೆಕ್ಟ್ಗಳನ್ನು ರಚಿಸುವ ಸಾಮರ್ಥ್ಯವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿದ್ದೀರಿ. ನೀವು ಈಗ ಡೇಟಾವನ್ನು ಲೇಜಿಯಾಗಿ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವ ಮೂಲಕ ಹೆಚ್ಚು ಮೆಮೊರಿ-ಪರಿಣಾಮಕಾರಿಯಾದ, ಪ್ರಮಾಣಿತ ಪೈಥಾನ್ ಸಿಂಟ್ಯಾಕ್ಸ್ನೊಂದಿಗೆ ಸ್ವಚ್ಛವಾಗಿ ಸಂಯೋಜಿಸುವ ಮೂಲಕ ಹೆಚ್ಚು ಅರ್ಥಗರ್ಭಿತವಾದ ಮತ್ತು ಅಂತಿಮವಾಗಿ ಹೆಚ್ಚು ಶಕ್ತಿಶಾಲಿ ವರ್ಗಗಳನ್ನು ಬರೆಯಬಹುದು. ಮುಂದಿನ ಬಾರಿ ನೀವು `for` ಲೂಪ್ ಅನ್ನು ಬರೆಯುವಾಗ, ಮೇಲ್ಮೈ ಅಡಿಯಲ್ಲಿ ನಡೆಯುತ್ತಿರುವ `__iter__` ಮತ್ತು `__next__` ನ ಸೊಗಸಾದ ನೃತ್ಯವನ್ನು ಶ್ಲಾಘಿಸಲು ಸ್ವಲ್ಪ ಸಮಯ ತೆಗೆದುಕೊಳ್ಳಿ.